From 0297039b380105e317913a4a57c0ab0f5159de78 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 8 Jan 2020 10:34:56 -0500 Subject: [PATCH] Add another dnd testcase This one tests nested drop sites and interaction between DND and other gestures. --- tests/meson.build | 1 + tests/testdnd3.c | 400 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 401 insertions(+) create mode 100644 tests/testdnd3.c diff --git a/tests/meson.build b/tests/meson.build index 8becf6a9f3..37d6f0d87f 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -31,6 +31,7 @@ gtk_tests = [ ['testdialog'], ['testdnd'], ['testdnd2'], + ['testdnd3'], ['testellipsise'], ['testemblems'], ['testentrycompletion'], diff --git a/tests/testdnd3.c b/tests/testdnd3.c new file mode 100644 index 0000000000..a2c5c8115b --- /dev/null +++ b/tests/testdnd3.c @@ -0,0 +1,400 @@ +#include + +static GdkContentProvider * +prepare (GtkDragSource *source, double x, double y) +{ + GtkWidget *canvas; + GtkWidget *item; + GdkContentProvider *provider; + GBytes *bytes; + + canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source)); + item = gtk_widget_pick (canvas, x, y, GTK_PICK_DEFAULT); + + if (!GTK_IS_LABEL (item)) + return NULL; + + bytes = g_bytes_new (&item, sizeof (gpointer)); + provider = gdk_content_provider_new_for_bytes ("CANVAS_ITEM", bytes); + g_bytes_unref (bytes); + + g_object_set_data (G_OBJECT (canvas), "dragged-item", item); + + return provider; +} + +static void +drag_begin (GtkDragSource *source, GdkDrag *drag) +{ + GtkWidget *canvas; + GtkWidget *item; + + canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source)); + item = g_object_get_data (G_OBJECT (canvas), "dragged-item"); + + gtk_widget_set_opacity (item, 0.5); +} + +static void +drag_end (GtkDragSource *source, GdkDrag *drag) +{ + GtkWidget *canvas; + GtkWidget *item; + + canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (source)); + item = g_object_get_data (G_OBJECT (canvas), "dragged-item"); + g_object_set_data (G_OBJECT (canvas), "dragged-item", NULL); + + gtk_widget_set_opacity (item, 1.0); +} + +typedef struct { + GtkWidget *canvas; + double x; + double y; +} DropData; + +typedef struct { + double x, y; + double angle; + double delta; +} TransformData; + +static void +apply_transform (GtkWidget *item) +{ + GtkWidget *canvas = gtk_widget_get_parent (item); + TransformData *data; + GskTransform *transform; + + data = g_object_get_data (G_OBJECT (item), "transform-data"); + transform = gsk_transform_rotate (gsk_transform_translate (NULL, &(graphene_point_t){data->x, data->y}), + data->angle + data->delta); + gtk_fixed_set_child_transform (GTK_FIXED (canvas), item, transform); + gsk_transform_unref (transform); +} + +static void +got_data (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + GdkDrop *drop = GDK_DROP (source); + DropData *data = user_data; + GInputStream *stream; + GBytes *bytes; + GtkWidget *item; + const char *mime_type; + GError *error = NULL; + TransformData *transform_data; + GtkWidget *canvas; + GtkWidget *last_child; + + stream = gdk_drop_read_finish (drop, result, &mime_type, &error); + bytes = g_input_stream_read_bytes (stream, sizeof (gpointer), NULL, NULL); + item = (gpointer) *(gpointer *)g_bytes_get_data (bytes, NULL); + + transform_data = g_object_get_data (G_OBJECT (item), "transform-data"); + + transform_data->x = data->x; + transform_data->y = data->y; + + canvas = gtk_widget_get_parent (item); + last_child = gtk_widget_get_last_child (canvas); + if (item != last_child) + gtk_widget_insert_after (item, canvas, last_child); + + apply_transform (item); + + gdk_drop_finish (drop, GDK_ACTION_MOVE); + + g_bytes_unref (bytes); + g_object_unref (stream); + g_free (data); +} + +static gboolean +drag_drop (GtkDropTarget *dest, + GdkDrop *drop, + int x, + int y) +{ + DropData *data; + + data = g_new (DropData, 1); + data->canvas = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)); + data->x = x; + data->y = y; + + gdk_drop_read_async (drop, (const char *[]){"CANVAS_ITEM", NULL}, G_PRIORITY_DEFAULT, NULL, got_data, data); + + return TRUE; +} + +static GtkWidget * +canvas_new (void) +{ + GtkWidget *canvas; + GtkDragSource *source; + GtkDropTarget *dest; + GdkContentFormats *formats; + + canvas = gtk_fixed_new (); + gtk_widget_set_hexpand (canvas, TRUE); + gtk_widget_set_vexpand (canvas, TRUE); + gtk_style_context_add_class (gtk_widget_get_style_context (canvas), "frame"); + + source = gtk_drag_source_new (); + gtk_drag_source_set_actions (source, GDK_ACTION_MOVE); + g_signal_connect (source, "prepare", G_CALLBACK (prepare), NULL); + g_signal_connect (source, "drag-begin", G_CALLBACK (drag_begin), NULL); + g_signal_connect (source, "drag-end", G_CALLBACK (drag_end), NULL); + gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (source)); + + formats = gdk_content_formats_new ((const char *[]){"CANVAS_ITEM", NULL}, 1); + dest = gtk_drop_target_new (formats, GDK_ACTION_MOVE); + g_signal_connect (dest, "drag-drop", G_CALLBACK (drag_drop), NULL); + gtk_widget_add_controller (canvas, GTK_EVENT_CONTROLLER (dest)); + gdk_content_formats_unref (formats); + + return canvas; +} + +static void +set_color (GtkWidget *item, + GdkRGBA *color) +{ + char *css; + char *str; + GtkStyleContext *context; + GtkCssProvider *provider; + + str = gdk_rgba_to_string (color); + css = g_strdup_printf ("* { background: %s; padding: 10px; }", str); + + context = gtk_widget_get_style_context (item); + provider = g_object_get_data (G_OBJECT (context), "style-provider"); + if (provider) + gtk_style_context_remove_provider (context, GTK_STYLE_PROVIDER (provider)); + + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_data (provider, css, -1); + gtk_style_context_add_provider (gtk_widget_get_style_context (item), GTK_STYLE_PROVIDER (provider), 800); + g_object_set_data_full (G_OBJECT (context), "style-provider", provider, g_object_unref); + + g_free (str); + g_free (css); +} + +static void +got_color (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GdkDrop *drop = GDK_DROP (source); + GtkDropTarget *dest = data; + GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (dest)); + const GValue *value; + GdkRGBA *color; + + value = gdk_drop_read_value_finish (drop, result, NULL); + color = g_value_get_boxed (value); + set_color (item, color); + + gdk_drop_finish (drop, GDK_ACTION_COPY); +} + +static gboolean +item_drag_drop (GtkDropTarget *dest, + GdkDrop *drop, + int x, + int y) +{ + if (gtk_drop_target_find_mimetype (dest)) + { + gdk_drop_read_value_async (drop, GDK_TYPE_RGBA, G_PRIORITY_DEFAULT, NULL, got_color, dest); + return TRUE; + } + + return FALSE; +} + +static gboolean +item_drag_motion (GtkDropTarget *dest, + GdkDrop *drop, + int x, + int y) +{ + if (gtk_drop_target_find_mimetype (dest) != NULL) + { + gdk_drop_status (drop, GDK_ACTION_COPY); + return TRUE; + } + + return FALSE; +} + +static void +angle_changed (GtkGestureRotate *gesture, + double angle, + double delta) +{ + GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)); + TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data"); + + data->delta = angle / M_PI * 180.0; + + apply_transform (item); +} + +static void +rotate_done (GtkGesture *gesture) +{ + GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)); + TransformData *data = g_object_get_data (G_OBJECT (item), "transform-data"); + + data->angle = data->angle + data->delta; + data->delta = 0; +} + +static void +click_done (GtkGesture *gesture) +{ + GtkWidget *item = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (gesture)); + GtkWidget *canvas = gtk_widget_get_parent (item); + GtkWidget *last_child; + + last_child = gtk_widget_get_last_child (canvas); + if (item != last_child) + gtk_widget_insert_after (item, canvas, last_child); +} + +static GtkWidget * +canvas_item_new (int i, + double x, + double y, + double angle) +{ + GtkWidget *widget; + char *label; + char *id; + TransformData *transform_data; + GdkRGBA rgba; + GtkDropTarget *dest; + GdkContentFormats *formats; + GtkGesture *gesture; + + label = g_strdup_printf ("Item %d", i); + id = g_strdup_printf ("item%d", i); + + gdk_rgba_parse (&rgba, "yellow"); + + widget = gtk_label_new (label); + gtk_style_context_add_class (gtk_widget_get_style_context (widget), "frame"); + gtk_widget_set_name (widget, id); + + set_color (widget, &rgba); + transform_data = g_new0 (TransformData, 1); + transform_data->x = x; + transform_data->y = y; + transform_data->angle = angle; + g_object_set_data_full (G_OBJECT (widget), "transform-data", transform_data, g_free); + + g_free (label); + g_free (id); + + formats = gdk_content_formats_new_for_gtype (GDK_TYPE_RGBA); + dest = gtk_drop_target_new (formats, GDK_ACTION_COPY); + g_signal_connect (dest, "drag-drop", G_CALLBACK (item_drag_drop), NULL); + g_signal_connect (dest, "drag-motion", G_CALLBACK (item_drag_motion), NULL); + gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (dest)); + gdk_content_formats_unref (formats); + + gesture = gtk_gesture_rotate_new (); + g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL); + g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL); + gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture)); + + gesture = gtk_gesture_click_new (); + g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL); + gtk_widget_add_controller (widget, GTK_EVENT_CONTROLLER (gesture)); + + return widget; +} + +int main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *sw; + GtkWidget *canvas; + GtkWidget *widget; + GtkWidget *box, *box2, *box3; + const char *colors[] = { + "red", "green", "blue", "magenta", "orange", "gray", "black", "yellow", + "white", "gray", "brown", "pink", "cyan", "bisque", "gold", "maroon", + "navy", "orchid", "olive", "peru", "salmon", "silver", "wheat", + NULL + }; + int i; + int x, y; + + gtk_init (); + + widget = gtk_color_button_new (); + gtk_widget_destroy (widget); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size (GTK_WINDOW (window), 640, 480); + + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_container_add (GTK_CONTAINER (window), box); + + box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_container_add (GTK_CONTAINER (box), box2); + + canvas = canvas_new (); + gtk_container_add (GTK_CONTAINER (box2), canvas); + + x = y = 40; + for (i = 0; i < 4; i++) + { + GtkWidget *item; + + item = canvas_item_new (i, x, y, 0); + gtk_container_add (GTK_CONTAINER (canvas), item); + apply_transform (item); + + x += 150; + y += 100; + } + + sw = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), + GTK_POLICY_AUTOMATIC, + GTK_POLICY_NEVER); + gtk_container_add (GTK_CONTAINER (box), sw); + + box3 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + gtk_style_context_add_class (gtk_widget_get_style_context (box3), "linked"); + gtk_container_add (GTK_CONTAINER (sw), box3); + + for (i = 0; colors[i]; i++) + { + GdkRGBA rgba; + GtkWidget *swatch; + + gdk_rgba_parse (&rgba, colors[i]); + + swatch = g_object_new (g_type_from_name ("GtkColorSwatch"), + "rgba", &rgba, + "selectable", FALSE, + NULL); + gtk_container_add (GTK_CONTAINER (box3), swatch); + } + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} -- 2.30.2